package org.test;

import java.util.*;

public class IndexFuncUtil {
    /**
     * 计算一段日期范围内‘组合收益率’和‘无风险收益率’的sharpe比率
     * @param arg1 double[],计算的日期范围内‘组合收益率’列表
     * @param arg2 double[],计算的日期范围内‘无风险收益率’列表
     * @param arg3 boolean,是否年化(true:是,false:否)
     * @param arg4 string,频率(D:日频(默认),W:周频，M:月频，频率决定年化方式)
     * @return double,sharpe比率数值
     */
    public static double sharpe(List<Double> arg1, List<Double> arg2, boolean arg3, String arg4) {
        if (arg1.size() <= 1) {
            return Double.NaN;
        }

        double mean1 = 0;
        double mean2 = 0;
        double std = 0;
        mean1 = NumCalcUtil.getMean(arg1);
        mean2 = NumCalcUtil.getMean(arg2);
        std = NumCalcUtil.getStdDeviation(arg1);

        if(std == 0) {
            return Double.NaN;
        }
        double sharpe = (mean1 - mean2) / std;
        if (arg3) {
            sharpe = NumCalcUtil.getYeared1(sharpe, arg4);
        }
        return sharpe;
    }

    /**
     * 计算一段日期范围内‘组合收益率’或‘基准收益率’的阶段值
     * @param arg1 double[],计算的日期范围内‘组合收益率’或‘基准收益率’的列表
     * @param arg2 int,年化天数
     * @param arg3 boolean,是否年化(true:是,false:否)
     * @param arg4 string,频率(D:日频(默认),W:周频，M:月频，频率决定年化方式)
     * @return double,区间收益率数值
     */
    public static double IntervalRat(List<Double> arg1, int arg2, boolean arg3, String arg4) {
        if (arg1.size() <= 0) {
            return Double.NaN;
        }

        double intvComRate = 0;
        intvComRate = NumCalcUtil.getIntervalYield(arg1);
        if (arg3) {
            intvComRate = NumCalcUtil.getYeared2(intvComRate, arg4, arg2);
        }
        return intvComRate - 1;
    }

    /**
     * 计算一段日期范围内‘组合收益率’的是否年化标准差的值
     * @param arg1 double[],计算的日期范围内‘组合收益率’的列表
     * @param arg2 boolean,是否年化(true:是,false:否)
     * @param arg3 string,频率(D:日频(默认),W:周频，M:月频，频率决定年化方式)
     * @return double,标准差数值
     */
    public static double std(List<Double> arg1, boolean arg2, String arg3) {
        if (arg1.size() <= 1) {
            return Double.NaN;
        }

        double std = 0;
        std = NumCalcUtil.getStdDeviation(arg1);
        if (arg2) {
            std = NumCalcUtil.getYeared1(std, arg3);
        }
        return std;
    }

    /**
     * 计算一段日期范围内‘组合收益率’和‘无风险收益率’的sortino比率
     * @param arg1 double[]，计算的日期范围内‘组合收益率’列表
     * @param arg2 double[]，计算的日期范围内‘无风险收益率’列表
     * @param arg3 double或null,‘组合收益率’临界值(传数值时用arg3做临界值，传null时用arg2‘无风险收益率’列表做临界值,默认0,取小于临界值的部分算下标准差)
     * @param arg4 boolean,是否年化(true:是,false:否)
     * @param arg5 string,频率(D:日频(默认)，W:周频，M:月频，频率决定年化方式)
     * @return double,sortino数值
     */
    public static double sortino(List<Double> arg1, List<Double> arg2, Object arg3, boolean arg4, String arg5) {
        //根据临界值过滤组合收益率
        List<Double> array = Collections.synchronizedList(new ArrayList<Double>());
        if (arg3 instanceof Double) {
            double bound = (Double) arg3;
            Iterator<Double> iter = arg1.iterator();
            while (iter.hasNext()) {
                double value = iter.next();
                if (value < bound) {
                    array.add(value);
                }
            }
        } else {
            for (int i = 0; i < arg1.size(); i++) {
                double ele = arg1.get(i) - arg2.get(i);
                if (ele < 0) {
                    array.add(ele);
                }
            }
        }

        //计算sortino
        double mean1 = 0;
        double mean2 = 0;
        if (array.size() <= 1) {
            return Double.NaN;
        }

        mean1 = NumCalcUtil.getMean(arg1);
        mean2 = NumCalcUtil.getMean(arg2);
        double dStd = NumCalcUtil.getStdDeviation(array);
        double sortino = (mean1 - mean2) / dStd;
        if (arg4) {
            sortino = NumCalcUtil.getYeared1(sortino, arg5);
        }
        return sortino;
    }

    /**
     * 计算一段日期范围内‘组合收益率’、‘市场指数收益率’、‘无风险收益率’的jensen指数
     * @param arg1 double数组，计算的日期范围内‘组合收益率’列表
     * @param arg2 double数组，计算的日期范围内‘市场指数收益率’列表
     * @param arg3 double,计算的日期范围内‘无风险收益率’列表
     * @param arg4 boolean,是否年化(true:是,false:否)
     * @param arg5 string,频率(D:日频(默认),W:周频，M:月频，频率决定年化方式)
     * @return double,jensen指数数值
     */
    public static double jenson(List<Double> arg1, List<Double> arg2, List<Double> arg3, boolean arg4, String arg5) {
        if (arg1.size() <= 1) {
            return Double.NaN;
        }

        //计算jenson
        double mean1 = 0;
        double mean2 = 0;
        double mean3 = 0;
        double cov = 0;
        double var = 0;
        mean1 = NumCalcUtil.getMean(arg1);
        mean2 = NumCalcUtil.getMean(arg2);
        mean3 = NumCalcUtil.getMean(arg3);
        cov = NumCalcUtil.getCovariance(arg1, arg2, mean1, mean2);
        var = NumCalcUtil.getVariance(arg2);
        if(var == 0) {
            return Double.NaN;
        }

        double beta = cov / var;
        double jensen = (mean1 - mean3) - beta * (mean2 - mean3);

        if (arg4) {
            jensen = NumCalcUtil.getYeared1(jensen, arg5);
        }

        return jensen;
    }

    /**
     * 计算一段日期范围内‘组合收益率’、‘基准收益率’、‘无风险收益率’的treynor指数
     * @param arg1 double数组，计算的日期范围内‘组合收益率’列表
     * @param arg2 double数组，计算的日期范围内‘基准收益率’列表
     * @param arg3 double数组，计算的日期范围内‘无风险收益率’列表
     * @param arg4 boolean，是否年化(true:是,false:否)
     * @param arg5 string，频率(D:日频(默认),W:周频，M:月频，频率决定年化方式)
     * @return double, treynor指数数值
     */
    public static double treynor(List<Double> arg1, List<Double> arg2, List<Double> arg3, boolean arg4, String arg5) {
        if (arg1.size() <= 1) {
            return Double.NaN;
        }

        //计算Treynor
        double rpMean = 0;
        double rfMean = 0;
        double cov = 0;
        double var = 0;
        rpMean = NumCalcUtil.getMean(arg1);
        rfMean = NumCalcUtil.getMean(arg3);
        cov = NumCalcUtil.getCovariance(arg1, arg2);
        var = NumCalcUtil.getVariance(arg2);

        if(cov == 0 || var == 0) {
            return Double.NaN;
        }
        double rpBeta = cov / var;
        double treynor = (rpMean - rfMean) / rpBeta;

        if (arg4) {
            treynor = NumCalcUtil.getYeared1(treynor, arg5);
        }

        return treynor;
    }

    /**
     * 计算一段日期范围内‘组合收益率’区间最大回撤
     * @param arg1 double数组，计算的日期范围内‘组合收益率’列表
     * @param arg2 string数组，计算的日期范围内‘日期’列表
     * @return double,区间最大回撤数值
     */
    public static double md(List<Double> arg1, List<String> arg2) {
        double[] virNet;
        virNet = NumCalcUtil.getVirtualUnitNet(arg1, arg2);

        double md = 0;
        if(virNet.length==0) {
            return md;
        }
        double minVirNet = virNet[virNet.length-1];
        for (int i = virNet.length; i > 0; i--) {
            minVirNet = virNet[i-1]<minVirNet? virNet[i-1] : minVirNet;
            double mdDay = virNet[i-1]==0? 0 : Math.abs(Math.min(0,(minVirNet - virNet[i-1]) / virNet[i-1]));
            md = mdDay>md? mdDay : md;
        }

        return md;
    }
}
